/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "Logger.h"

#include <stdarg.h>
#include <time.h>
#include <windows.h>//platform dependent need change

#include "utf8.h"

namespace PQCore
{
	bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
	{
		try{
			size_t len = utf8::distance(utf8str,utf8str+csize);
			if(len > wsize)
			{
				if(wsize > 0)
					wstr[0] = L'\0';
				wsize = 0;
				return false;
			}

			wsize = len;
			utf8::utf8to16(utf8str,utf8str+csize,wstr);
			wstr[len] = L'\0';
		}catch(std::exception){
			if(wsize > 0)
				wstr[0] = L'\0';
			wsize = 0;
			return false;
		}

		return true;
	}

	void vutf8printf(FILE *out, const char *str, va_list* ap)
	{
	#ifdef WIN32
		char temp_buf[32*1024];
		wchar_t wtemp_buf[32*1024];

		size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap);

		size_t wtemp_len = 32*1024-1;
		Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);

		CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1);
		fprintf(out, temp_buf);
	#else
		vfprintf(out, str, *ap);
	#endif
	}


	Logger::Logger()
	{
		/// Open specific log files
		_file = open("file","flag","w");
	}

	FILE* Logger::open(char const* name,char const* flag, char const* mode)
	{
		//should use configration to load file
		return fopen("log.txt", mode);
	}
	
	void Logger::logError(const char * err, ...)
	{
		if (!err){
			return;
		}

		//maybe should write to db
		va_list ap;
		va_start(ap, err);
		vutf8printf(stderr, err, &ap);
		va_end(ap);

		fprintf( stderr, "\n");
		if (_file){
			outTimestamp(_file);
			fprintf(_file, "ERROR: ");

			va_start(ap, err);
			vfprintf(_file, err, ap);
			va_end(ap);

			fprintf(_file, "\n");
			fflush(_file);
		}
		fflush(stderr);
	}

	void Logger::outErrorDb(const char * str, ...)
	{
	}

	void Logger::outDetail(const char * str, ...)
	{
		if (!str){
			return;
		}

		//maybe need to write db too
		va_list ap;

		va_start(ap, str);
		vutf8printf(stdout, str, &ap);
		va_end(ap);

		printf("\n");
		if(_file){
			outTimestamp(_file);
			va_start(ap, str);
			vfprintf(_file, str, ap);
			fprintf(_file, "\n");
			va_end(ap);

			fflush(_file);
		}
		fflush(stdout);
	}


	void Logger::logDebug(const char * str, ...)
	{
		if (!str){
			return;
		}

		//maybe need to write db too
		va_list ap;

		va_start(ap, str);
		vutf8printf(stdout, str, &ap);
		va_end(ap);

		printf("\n");
		if(_file){
			outTimestamp(_file);
			va_start(ap, str);
			vfprintf(_file, str, ap);
			fprintf(_file, "\n");
			va_end(ap);

			fflush(_file);
		}
		fflush(stdout);
	}

	void Logger::outBasic(const char * str, ...)
	{
		if (!str){
			return;
		}

		//maybe need to write db too
		va_list ap;

		va_start(ap, str);
		vutf8printf(stdout, str, &ap);
		va_end(ap);

		printf("\n");
		if(_file){
			outTimestamp(_file);
			va_start(ap, str);
			vfprintf(_file, str, ap);
			fprintf(_file, "\n");
			va_end(ap);

			fflush(_file);
		}
		fflush(stdout);
	}

	void Logger::log(const char * str, ...)
	{
		if (!str){
			return;
		}

		//maybe need to write db too
		va_list ap;

		va_start(ap, str);
		vutf8printf(stdout, str, &ap);
		va_end(ap);

		printf("\n");
		if(_file){
			outTimestamp(_file);
			va_start(ap, str);
			vfprintf(_file, str, ap);
			fprintf(_file, "\n");
			va_end(ap);

			fflush(_file);
		}
		fflush(stdout);
	}

	void Logger::outDB()
	{
	  
	}


	void Logger::outLine()
	{
		printf("\n");
		if (_file){
			outTimestamp(_file);
			fprintf(_file, "\n");
			fflush(_file);
		}
		fflush(stdout);
	}

	void Logger::outTimestamp(FILE* file)
	{
		time_t t = time(NULL);
		tm* aTm = localtime(&t);
		//       YYYY   year
		//       MM     month (2 digits 01-12)
		//       DD     day (2 digits 01-31)
		//       HH     hour (2 digits 00-23)
		//       MM     minutes (2 digits 00-59)
		//       SS     seconds (2 digits 00-59)
		fprintf(file,"%-4d-%02d-%02d %02d:%02d:%02d ",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
	}
}
